#pragma once

//I am working in VS2010 Proffesional - here I have some utin testing 
//framework but if I using it i have problem while including any ihter files :*( so...
//My alternative for MS unit-testing =)

#include "Point3d.h"
#include "Vector3d.h"
#include "Plane3d.h"
#include "Line3d.h"

#include <iostream>
#include <vector>
#include <string>

class Test
  {
  public:
    Test()
      {
      PointDistanceTest();

      VectorCoordinatesTest();
      VectorLengthTest();
      VectorAngleTest();
      VectorVectorPlusVectorTest();
      VectorScalarProduct();
      VectorVectorProduct();
      VectorMixedProduct();

      PlaneAttributesTest();
      PlaneIsParallelTest();
      PlaneIsPerpendicularTest();
      PlaneDistanceTest();
      PlaneTheSamePlaneTest();
      }

    void OutputData()
      {
      std::cout << "Unit tests" << std::endl;
      auto text_iter = m_test_names.begin();
      for(auto iter = m_test_result_data.begin();
        iter != m_test_result_data.end();
        ++iter)
        {
        std::cout << (*text_iter) << " = ";
        if((*iter))
          std::cout << "GREEN" << std::endl;
        else
          std::cout << "RED" << std::endl;
        ++text_iter;
        }
      }

    void PointDistanceTest()
      {
      _SetName("PointDistanceTest");
      Point3d point1(0,0,0);
      Point3d point2(1,2,2);
      if( fabs(point1.GetDistance(point2) - 3) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }

    void VectorCoordinatesTest()
      {
      _SetName("VectorCoordinatesTest");
      Vector3d vector(Point3d(2,1,0), Point3d(5,2,0));
      if( fabs(vector.GetX() - 3) > EPS )
        {
        _Assert(false);
        return ;
        }
      if( fabs(vector.GetY() - 1) > EPS )
        {
        _Assert(false);
        return ;
        }
      if( fabs(vector.GetZ() - 0) > EPS )
        {
        _Assert(false);
        return ;
        }
      _Assert(true);
      return ;
      }
    void VectorLengthTest()
      {
      _SetName("VectorLengthTest");
      Vector3d vector(3,1,0);
      if( fabs(vector.GetLength() - sqrt(10.0)) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void VectorAngleTest()
      {
      _SetName("VectorAngleTest");
      Vector3d vector1(3,1,0);
      Vector3d vector2(4,0,0);
      if( fabs(vector1.GetAngle(vector2) - 18.4349488) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void VectorVectorPlusVectorTest()
      {
      _SetName("VectorVectorPlusVectorTest");
      Vector3d vector1(3,1,0);
      Vector3d vector2(4,0,0);
      Vector3d vector3 = vector1 + vector2;
      if( fabs(vector3.GetX() - 7) > EPS)
        {
        _Assert(false);
        return;
        }
      if( fabs(vector3.GetY() - 1) > EPS)
        {
        _Assert(false);
        return;
        }
      if( fabs(vector3.GetZ() - 0) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void VectorScalarProduct()
      {
      _SetName("VectorScalarProduct");
      Vector3d vector1(3,1,0);
      Vector3d vector2(4,0,0);
      double result = vector1 * vector2;
      if( fabs(result - 12) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void VectorVectorProduct()
      {
      _SetName("VectorVectorProduct");
      Vector3d vector1(3,1,0);
      Vector3d vector2(4,0,0);
      Vector3d vector3 = vector1 ^ vector2;
      if( fabs(vector3.GetX() - 0) > EPS)
        {
        _Assert(false);
        return;
        }
      if( fabs(vector3.GetY() - 0) > EPS)
        {
        _Assert(false);
        return;
        }
      if( fabs(vector3.GetZ() - (-4)) > EPS)
        {
        _Assert(false);
        return;
        }

      _Assert(true);
      }
    void VectorMixedProduct()
      {
      _SetName("VectorMixedProduct");
      Vector3d vector1(3,1,0);
      Vector3d vector2(4,0,0);
      Vector3d vector3(5,3,2);
      double result = vector1.MixedProduct(vector1, vector2, vector3);
      if( fabs(result - (-8)) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }

    void PlaneAttributesTest()
      {
      _SetName("PlaneAttributesTest");
      Plane3d plane(Point3d(1,5,3), Point3d(2,1,4), Point3d(3,2,1));
      if(fabs(plane.GetA() - 11) > EPS)
        {
        _Assert(false);
        return;
        }
      if(fabs(plane.GetB() - 4) > EPS)
        {
        _Assert(false);
        return;
        }
      if(fabs(plane.GetC() - 5) > EPS)
        {
        _Assert(false);
        return;
        }
      if(fabs(plane.GetD() - (-46)) > EPS)
        {
        _Assert(false);
        return;
        }
      _Assert(true);

      }
    void PlaneIsParallelTest()
      {
      _SetName("PlaneParallelTest");
      Plane3d plane1(2,4,6,10);
      Plane3d plane2(1,2,3,4);
      if(!plane1.IsParallel(plane2))
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void PlaneIsPerpendicularTest()
      {
      _SetName("PlanePerpendicularTest");
      Plane3d plane1(0,0,0,15);
      Plane3d plane2(0,0,0,20);
      if(!plane1.IsPerpendicular(plane2))
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void PlaneDistanceTest()
      {
      _SetName("PlaneDistanceTest");
      Plane3d plane(1,2,3,4);
      Point3d point(1,2,3);
      double distance = plane.GetDistanceFromPoint(point);
      
      if( fabs(distance - 4.81) > 0.01 )
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
    void PlaneTheSamePlaneTest()
      {
      _SetName("PlaneTheSamePlaneTest");
      Plane3d plane1(2,4,6,8);
      Plane3d plane2(1,2,3,4);
      if(!plane1.IsSame(plane2))
        {
        _Assert(false);
        return;
        }
      _Assert(true);
      }
  private:
    void _SetName(std::string i_name)
      {
      m_test_names.push_back(i_name);
      }
    void _Assert(bool i_value)
      {
      m_test_result_data.push_back(i_value);
      }

  private:
    std::vector<std::string> m_test_names;
    std::vector<bool> m_test_result_data;
  };